﻿using System;
using System.Linq;
using System.Drawing;
using System.Windows.Forms;
using LinqKit;
using Syncfusion.Grouping;
using Syncfusion.Windows.Forms.Grid;
using Syncfusion.Windows.Forms.Grid.Grouping;
using PMngr.Data;

namespace PMngr.Main
{
    public partial class SubUnits : BaseControl
    {
        private IRepositoryFactory repositoryFactory;
        private Unit _upUnit;

        public SubUnits()
        {
            InitializeComponent();
            InitializeGridGrouping();
        }

        public SubUnits(IRepositoryFactory repositoryFactory) : this()
        {
            this.repositoryFactory = repositoryFactory;                 
        }

        public override void InitializeControls()
        {
            comUpUnit.SelectedIndexChanged -= ComUpUnitSelectedIndexChanged;
            comUnitType.SelectedIndexChanged -= ComUnitTypeSelectedIndexChanged;
            comUnitKind.SelectedValueChanged -= ComUnitKindSelectedValueChanged;
            // 单位区域
            InitializeDropDownList();
            // 主管部门
            InitializeComboBox();

            comUpUnit.SelectedIndexChanged += ComUpUnitSelectedIndexChanged;
            comUnitType.SelectedIndexChanged += ComUnitTypeSelectedIndexChanged;
            comUnitKind.SelectedValueChanged += ComUnitKindSelectedValueChanged;

            ComUpUnitSelectedIndexChanged(this, EventArgs.Empty);
        }
        
        #region GridGroupingControl Settings
        private void InitializeGridGrouping()
        {
            var gcd = new GridColumnDescriptor(UnitModel.GetPropertyName(u => u.Id),
                                               UnitModel.GetPropertyName(u => u.Id),
                                               UnitModel.Dict[UnitModel.GetPropertyName(u => u.Id)]);
            glSubsidiaries.TableDescriptor.Columns.Add(gcd);
            var gcd1 = new GridColumnDescriptor(UnitModel.GetPropertyName(u => u.Name),
                                                UnitModel.GetPropertyName(u => u.Name),
                                                UnitModel.Dict[UnitModel.GetPropertyName(u => u.Name)]) {Width = 200};
            glSubsidiaries.TableDescriptor.Columns.Add(gcd1);
            var gcd2 = new GridColumnDescriptor(UnitModel.GetPropertyName(u => u.UnitKind),
                                                UnitModel.GetPropertyName(u => u.UnitKind),
                                                UnitModel.Dict[UnitModel.GetPropertyName(u => u.UnitKind)], true, 90);
            glSubsidiaries.TableDescriptor.Columns.Add(gcd2);
            var gcd3 = new GridColumnDescriptor(UnitModel.GetPropertyName(u => u.Capacity),
                                                UnitModel.GetPropertyName(u => u.Capacity),
                                                UnitModel.Dict[UnitModel.GetPropertyName(u => u.Capacity)], true, 75);
            glSubsidiaries.TableDescriptor.Columns.Add(gcd3);
            var gcd4 = new GridColumnDescriptor(UnitModel.GetPropertyName(u => u.Contact),
                                                UnitModel.GetPropertyName(u => u.Contact),
                                                UnitModel.Dict[UnitModel.GetPropertyName(u => u.Contact)], true, 80);
            glSubsidiaries.TableDescriptor.Columns.Add(gcd4);
            var gcd5 = new GridColumnDescriptor(UnitModel.GetPropertyName(u => u.ContactTel),
                                                UnitModel.GetPropertyName(u => u.ContactTel),
                                                UnitModel.Dict[UnitModel.GetPropertyName(u => u.ContactTel)], true, 100);
            glSubsidiaries.TableDescriptor.Columns.Add(gcd5);
            var gcd6 = new GridColumnDescriptor(UnitModel.GetPropertyName(u => u.SuperUnit),
                                                UnitModel.GetPropertyName(u => u.SuperUnit),
                                                UnitModel.Dict[UnitModel.GetPropertyName(u => u.SuperUnit)], true, 200);
            glSubsidiaries.TableDescriptor.Columns.Add(gcd6);
            var gcd7 = new GridColumnDescriptor(UnitModel.GetPropertyName(u => u.Address),
                                                UnitModel.GetPropertyName(u => u.Address),
                                                UnitModel.Dict[UnitModel.GetPropertyName(u => u.Address)], true, 200);
            glSubsidiaries.TableDescriptor.Columns.Add(gcd7);
            glSubsidiaries.TableDescriptor.FrozenColumn = UnitModel.GetPropertyName(u => u.Name);
            // hide the trivial items
            glSubsidiaries.TableDescriptor.VisibleColumns.Remove(UnitModel.GetPropertyName(u => u.Id));

            glSubsidiaries.InitializeGridGroupingWithFilterAndFormat("[IsValid] LIKE 'false'");

            glSubsidiaries.DataSource = null;
            // event
            glSubsidiaries.TableControlMouseDown += GlSubsidiariesTableControlMouseDown;
        }
        #endregion

        void GlSubsidiariesTableControlMouseDown(object sender, GridTableControlMouseEventArgs e)
        {
            if (e.Inner.Button == MouseButtons.Right)
            {
                int row, col;
                var pt = new Point(e.Inner.X, e.Inner.Y);

                if (e.TableControl.PointToRowCol(pt, out row, out col))
                    e.TableControl.CurrentCell.AdjustRowColIfCoveredCell(ref row, ref col);

                GridTableCellStyleInfo style = e.TableControl.GetTableViewStyleInfo(row, col);
                if (style.TableCellIdentity.DisplayElement.Kind != DisplayElementKind.ColumnHeader)
                    contextMenu.Show(e.TableControl, pt);
            }
        }

        private void InitializeDropDownList()
        {
            using (var repository = repositoryFactory.CreateRepository())
            {
                // 单位区域
                var options1 = repository.All<ItemBase>();
                var datasource1 = from o in options1
                                  where o.Type == "UnitType" && o.IsValid
                                  orderby o.Order
                                  select new {o.Code, o.Name};
                var result1 = datasource1.ToList();
                result1.Insert(0, new {Code = DefaultAll.DefaultValue, Name = DefaultAll.DefaultName});
                comUnitType.DataSource = result1;
                comUnitType.DisplayMember = ItemModel.GetPropertyName(u => u.Name);
                comUnitType.ValueMember = ItemModel.GetPropertyName(u => u.Code);
                // 增强型需求
                comUnitType.ImageList = imageList;
                var count = comUnitType.ImageIndexes.Count;
                for (var i = 0; i < count; i++)
                    comUnitType.ImageIndexes[i] = 0;
                // 单位性质
                var options2 = repository.All<ItemBase>();
                var datasource2 = from o in options2
                                  where o.Type == "UnitKind" && o.IsValid
                                  orderby o.Order
                                  select new {o.Code, o.Name};
                var kinds = datasource2.ToList();
                comUnitKind.DataSource = kinds;
                comUnitKind.DisplayMember = ItemModel.GetPropertyName(u => u.Name);
                comUnitKind.ValueMember = ItemModel.GetPropertyName(u => u.Code);
            }
        }

        private void InitializeComboBox()
        {
            using (var repository = repositoryFactory.CreateRepository())
            {
                // 主管部门
                var units = repository.Find<Unit>(u => u.IsValid && u.ParentUnit == null);
                var datasource = from u in units
                                 select new {u.Id, u.Name};

                var result = datasource.ToList();
                result.Insert(0, new {Id = DefaultAll.DefaultValue, Name = DefaultAll.DefaultName});
                comUpUnit.DataSource = result;
                comUpUnit.DisplayMember = UnitModel.GetPropertyName(u => u.Name);
                comUpUnit.ValueMember = UnitModel.GetPropertyName(u => u.Id);
                // settings
                GridControl grid = comUpUnit.ListBox.Grid;
                grid.Cols.DefaultSize = 230;
                grid.HideCols[UnitModel.GetPropertyName(u => u.Id)] = true;
                grid.PrepareViewStyleInfo += gridList_PrepareViewStyleInfo;
            }
        }

        private void gridList_PrepareViewStyleInfo(object sender, GridPrepareViewStyleInfoEventArgs e)
        {
            if (e.ColIndex == 2 && e.RowIndex == 0)
            {
                e.Style.Text = Utilities.MajorUnitSelected;
            }           
        }

        private void ResetDetails()
        {
            txtUnit.Text = "";
            txtAddress.Text = "";
            txtContact.Text = "";
            txtTel.Text = "";
            txtDesc.Text = "";
            chkValid.Checked = true;
            nudCapacity.Enabled = false;
            nudCapacity.Value = 0;
        }

        private void ResetGrid(int unitType, int unitPId, int? unitId)
        {
            using (var repository = repositoryFactory.CreateRepository())
            {
                var predicate = PredicateBuilder.True<Unit>();
                predicate = predicate.And(u => u.ParentUnit != null && u.ParentUnit.IsValid);

                if (unitType != -1)
                    predicate = predicate.And(u => u.ParentUnit.UnitType.Code == unitType);
                if (unitPId != -1)
                    predicate = predicate.And(u => u.ParentUnit.Id == unitPId);

                var datasource = repository.Find(predicate.Expand());
                var result = from u in datasource
                             orderby u.Id
                             select new UnitModel
                                        {
                                            Id = u.Id,
                                            Name = u.Name,
                                            UnitKind = u.UnitType.Name,
                                            Capacity = u.Capacity,
                                            Contact = u.Contact,
                                            ContactTel = u.ContactTel,
                                            SuperUnit = u.ParentUnit.Name,
                                            Address = u.Address,
                                            IsValid = u.IsValid
                                        };

                glSubsidiaries.DataSource = result.ToList();
                // set the selected item in current row status
                if (glSubsidiaries.Table.Records.Count > 0)
                {
                    foreach (Record record in glSubsidiaries.Table.Records)
                    {
                        if (record.IsRecord())
                        {
                            var value = record.GetValue(UnitModel.GetPropertyName(u => u.Id));
                            if (value != null)
                            {
                                if (unitId == (int) value)
                                {
                                    glSubsidiaries.Table.SelectedRecords.Add(record);
                                    glSubsidiaries.Table.CurrentRecord = record;
                                }
                            }
                        }
                    }
                }
                else
                {
                    ResetDetails();
                }
            }
        }

        private void ResetGridByIndex(int unitType, int unitPId, int index)
        {
            using (var repository = repositoryFactory.CreateRepository())
            {
                var predicate = PredicateBuilder.True<Unit>();
                predicate = predicate.And(u => u.ParentUnit != null && u.ParentUnit.IsValid);

                if (unitType != -1)
                    predicate = predicate.And(u => u.ParentUnit.UnitType.Code == unitType);
                if (unitPId != -1)
                    predicate = predicate.And(u => u.ParentUnit.Id == unitPId);

                var datasource = repository.Find(predicate.Expand());
                var result = from u in datasource
                             orderby u.Id
                             select new UnitModel
                                        {
                                            Id = u.Id,
                                            Name = u.Name,
                                            UnitKind = u.UnitType.Name,
                                            Capacity = u.Capacity,
                                            Contact = u.Contact,
                                            ContactTel = u.ContactTel,
                                            SuperUnit = u.ParentUnit.Name,
                                            Address = u.Address,
                                            IsValid = u.IsValid
                                        };

                glSubsidiaries.DataSource = result.ToList();

                if (glSubsidiaries.Table.Records.Count > 0)
                {
                    glSubsidiaries.Table.CurrentRecord = glSubsidiaries.Table.Records[index];
                    //glSubsidiaries.Table.SelectedRecords.Add(glSubsidiaries.Table.Records[index]);
                }
                else
                {
                    ResetDetails();
                }
            }
        }

        private bool CheckUnitName(string name)
        {
            using (var repository = repositoryFactory.CreateRepository())
            {
                var units = repository.Find<Unit>(u => u.IsValid && u.Name == name && u.UnitType.Type == "UnitKind");
                return units.Any();
            }
        } 

        private void BtnSaveClick(object sender, EventArgs e)
        {
            var upUnitId = (int)comUpUnit.SelectedValue;
            if (upUnitId == -1 && _upUnit == null)
            {
                MessageFactory.Show(Utilities.MajorUnitFirstRequired);
                return;
            }

            if (String.IsNullOrWhiteSpace(txtUnit.Text))
            {
                MessageFactory.Show(Utilities.UnitRequired);
                return;
            }

            var isExist = CheckUnitName(txtUnit.Text);

            using (var repository = repositoryFactory.CreateRepository())
            {
                Record selected;
                var selecteds = glSubsidiaries.Table.SelectedRecords;
                try
                {
                    if (selecteds != null && selecteds.Count > 0)
                    {
                        // get the Unit Id
                        selected = selecteds[0].Record;
                        var unitId = (int) selected.GetValue("Id");

                        var item = repository.Find<Unit>(unitId);
                        // Validate the ItemBase model
                        if ((item.Name != txtUnit.Text) && isExist)
                        {
                            MessageFactory.Show(String.Format(Utilities.NameDuplicated, txtUnit.Text));
                            return;
                        }

                        var unitTypeId = (int) comUnitType.SelectedValue;
                        var unitKind = repository.Find<ItemBase>((int) comUnitKind.SelectedValue);
                        item.Name = txtUnit.Text;
                        item.Description = txtDesc.Text;
                        item.Address = txtAddress.Text;
                        item.Contact = txtContact.Text;
                        item.ContactTel = txtTel.Text;
                        item.IsValid = chkValid.Checked;
                        item.Capacity = (int) nudCapacity.Value;
                        item.UnitType = unitKind;

                        repository.TrySave<Unit>();

                        var unitPId = (int) comUpUnit.SelectedValue;
                        var index = glSubsidiaries.Table.Records.IndexOf(selected);
                        ResetGridByIndex(unitTypeId, unitPId, index);

                        LogTrace(String.Format(Utilities.SuccessUpdated, item.Name));
                    }
                    else
                    {
                        if (isExist)
                        {
                            MessageFactory.Show(String.Format(Utilities.NameDuplicated, txtUnit.Text));
                            return;
                        }
                        // get the UnitType Id
                        var unitTypeId = (int) comUnitType.SelectedValue;
                        var unitKindId = (int) comUnitKind.SelectedValue;
                        var unitKind = repository.Find<ItemBase>(unitKindId);

                        var unitPId = (int) comUpUnit.SelectedValue;
                        var unit = repository.Find<Unit>(unitPId);

                        var item = new Unit
                                       {
                                           Name = txtUnit.Text,
                                           UnitType = unitKind,
                                           Description = txtDesc.Text,
                                           Address = txtAddress.Text,
                                           Contact = txtContact.Text,
                                           ContactTel = txtTel.Text,
                                           IsValid = chkValid.Checked,
                                           CreateDate = DateTime.Now,
                                           ParentUnit = unit,
                                           Capacity = (int) nudCapacity.Value
                                       };

                        repository.Add(item);
                        repository.TrySave<Unit>();

                        ResetGrid(unitTypeId, unitPId, item.Id);
                        LogTrace(String.Format(Utilities.SuccessUnitAdded, item.Name));
                    }
                }
                catch (ValidationException ex)
                {
                    var message = String.Empty;
                    foreach (var entity in ex.Errors)
                    {
                        message = entity.Errors.Aggregate(message,
                                                          (current, error) =>
                                                          current +
                                                          String.Format("Property:'{0}' Error:{1}\r\n", error.Property,
                                                                        error.Message));
                    }
                    LogTrace(message, MessageType.Error);
                }
            }
        }
       
        private void GlSubsidiariesSelectedRecordsChanged(object sender, SelectedRecordsChangedEventArgs e)
        {
            if (e.Action == SelectedRecordsChangedType.Added)
            {
                var selecteds = glSubsidiaries.Table.SelectedRecords;
                if (selecteds != null && selecteds.Count > 0)
                {
                    var unitId = (int)selecteds[0].Record.GetValue(UnitModel.GetPropertyName(u => u.Id));
                    BuildUpDetails(unitId);
                }
            }
        }

        private void BuildUpDetails(int? unitId)
        {
            using (var repository = repositoryFactory.CreateRepository())
            {
                if (unitId.HasValue)
                {
                    var unit = repository.Find<Unit>(unitId);
                    _upUnit = unit.ParentUnit;

                    txtUnit.Text = unit.Name;
                    txtAddress.Text = unit.Address;
                    txtContact.Text = unit.Contact;
                    txtTel.Text = unit.ContactTel;
                    txtDesc.Text = unit.Description;
                    chkValid.Checked = unit.IsValid;
                    nudCapacity.Value = unit.Capacity;
                    if (unit.UnitType != null)
                    {
                        var selectdValue = comUnitKind.SelectedValue;

                        comUnitKind.SelectedValue = unit.UnitType.Code;
                        if (selectdValue != null && (int) selectdValue == unit.UnitType.Code)
                            ComUnitKindSelectedValueChanged(this, EventArgs.Empty);
                    }
                }
            }
        }

        private void ComUnitTypeSelectedIndexChanged(object sender, EventArgs e)
        {
            SetUnits();

            var unitType = (int)comUnitType.SelectedValue;
            var unit = DefaultAll.DefaultValue;
            if (comUpUnit.SelectedValue != null)
                unit = (int)comUpUnit.SelectedValue;

            ResetGridByIndex(unitType, unit, 0);           
        }

        private void ComUpUnitSelectedIndexChanged(object sender, EventArgs args)
        {
            var unitType = (int)comUnitType.SelectedValue;
            var unit = DefaultAll.DefaultValue;
            if (comUpUnit.SelectedValue != null)
            {
                unit = (int)comUpUnit.SelectedValue;
                using (var repository = repositoryFactory.CreateRepository())
                {
                    _upUnit = repository.Find<Unit>(unit);
                }
            }

            ResetGridByIndex(unitType, unit, 0);           
        }
        
        private void SetUnits()
        {
            var unitType = comUnitType.SelectedValue;
            // 主管部门
            if ((int)unitType == -1)
            {
                InitializeComboBox();
            }
            else
            {
                using (var repository = repositoryFactory.CreateRepository())
                {
                    var units =
                        repository.Find<Unit>(
                            item => item.IsValid && item.ParentUnit == null && item.UnitType.Code == (int) unitType);
                    var datasource = from u in units
                                     select new {u.Id, u.Name};

                    var result = datasource.ToList();
                    result.Insert(0, new {Id = DefaultAll.DefaultValue, Name = DefaultAll.DefaultName});
                    comUpUnit.DataSource = result;
                    comUpUnit.DisplayMember = UnitModel.GetPropertyName(u => u.Name);
                    comUpUnit.ValueMember = UnitModel.GetPropertyName(u => u.Id);
                }
            }
        }

        private void AddNewUnitToolStripMenuItemClick(object sender, EventArgs e)
        {
            var unitId = (int)comUpUnit.SelectedValue;
            if (unitId == -1)
            {
                MessageFactory.Show(Utilities.MajorUnitFirstRequired, MessageType.Exclamation);
                return;
            }

            glSubsidiaries.Table.SelectedRecords.Clear();
            ResetDetails();
        }

        private void ComUnitKindSelectedValueChanged(object sender, EventArgs e)
        {
            if (_upUnit == null) return;

            var unitType = _upUnit.UnitType.Name;
            var unitKind = comUnitKind.Text;
         
            nudCapacity.Enabled = false;
            // 市直和县区的机关、参公、全额、差额、自收自支事业单位要编制，其他的都不要编制
            if (unitType == "市直" || unitType == "县区")
            {
                if (unitKind.Contains("机关") || unitKind.Contains("参公") ||
                    unitKind.Contains("全额") || unitKind.Contains("差额") || unitKind.Contains("自收自支"))
                {
                    nudCapacity.Enabled = true;
                }
            }
        }
    }
}
